#include "BasicType/String.h"
#include <string.h>

namespace GCRE {
	namespace BasicType {

		String::String() : data( NULL ), length( 0 )
		{
			data = new SFChar[1];
			data[0] = '\0';
		}

		String::String( const String& s )
		{
			length = s.length;
			data = new SFChar[length + 1];
			strcpy_s( data, length + 1, s.data );
		}

		String::String( const SFChar* c )
		{
			length = strlen( c );
			data = new SFChar[length + 1];
			strcpy_s( data, length + 1, c );
		}

		String::String( SFInt len )
		{
			data = new SFChar[len + 1];
			data[len] = '\0';
			length = len;
		}

		String::~String()
		{
			delete[] data;
			data = NULL;
		}

		String& String::operator=( const String& s )
		{
			delete[] data;
			length = s.length;
			data = new SFChar[length + 1];
			strcpy_s( data, length + 1, s.data );
			return *this;
		}

		String& String::operator=( const SFChar* c )
		{
			delete[] data;
			length = strlen( c );
			data = new SFChar[length + 1];
			strcpy_s( data, length + 1, c );
			return *this;
		}

		String String::operator+( const String& s ) const
		{
			String result( length + s.length );

			strcpy_s( result.data, result.length + 1, data );
			strcat_s( result.data, result.length + 1, s.data );

			return result;
		}

		String String::operator+( const SFChar* c ) const
		{
			String result( length + strlen( c ) );

			strcpy_s( result.data, result.length + 1, data );
			strcat_s( result.data, result.length + 1, c );

			return result;
		}

		SFBool String::operator==( const String& s ) const
		{
			if ( strcmp( data, s.data ) == 0 )
				return true;
			else
				return false;
		}

		SFBool String::operator==( const SFChar* c ) const
		{
			if ( strcmp( data, c ) == 0 )
				return true;
			else
				return false;
		}

		SFBool String::operator!=( const String& s ) const
		{
			if ( strcmp( data, s.data ) == 0 )
				return false;
			else
				return true;
		}

		SFBool String::operator!=( const SFChar* c ) const
		{
			if ( strcmp( data, c ) == 0 )
				return false;
			else
				return true;
		}

		SFBool String::operator>( const String& s ) const
		{
			if ( strcmp( data, s.data ) > 0 )
				return true;
			else
				return false;
		}

		SFBool String::operator>( const SFChar* c ) const
		{
			if ( strcmp( data, c ) > 0 )
				return true;
			else
				return false;
		}

		SFBool String::operator<( const String& s ) const
		{
			if ( strcmp( data, s.data ) < 0 )
				return true;
			else
				return false;
		}

		SFBool String::operator<( const SFChar* c ) const
		{
			if ( strcmp( data, c ) < 0 )
				return true;
			else
				return false;
		}

		SFBool String::operator>=( const String& s ) const
		{
			if ( strcmp( data, s.data ) >= 0 )
				return true;
			else
				return false;
		}

		SFBool String::operator>=( const SFChar* c ) const
		{
			if ( strcmp( data, c ) >= 0 )
				return true;
			else
				return false;
		}

		SFBool String::operator<=( const String& s ) const
		{
			if ( strcmp( data, s.data ) <= 0 )
				return true;
			else
				return false;
		}

		SFBool String::operator<=( const SFChar* c ) const
		{
			if ( strcmp( data, c ) <= 0 )
				return true;
			else
				return false;
		}

		String& String::operator+=( const SFChar* c )
		{
			length += strlen( c );
			SFChar* new_data = new SFChar[length + 1];
			strcpy_s( new_data, length + 1, data );
			strcat_s( new_data, length + 1, c );
			delete[] data;
			data = new_data;
			return *this;
		}

		String& String::operator+=( const String& s )
		{
			length += s.length;
			SFChar* new_data = new SFChar[length + 1];
			strcpy_s( new_data, length + 1, data );
			strcat_s( new_data, length + 1, s.data );
			delete[] data;
			data = new_data;
			return *this;
		}

		void String::Swap( String& s )
		{
			SFInt l = length;
			length = s.length;
			s.length = l;

			SFChar* tmp = data;
			data = s.data;
			s.data = tmp;
		}

		int String::find( SFChar c, SFInt pos /*= 0 */ ) const
		{
			assert( pos >= 0 && pos < length );
			SFInt nfind = -1;
			while( pos < length )
			{
				if ( data[pos] == c )
				{
					nfind = pos;
					break;
				}
				++pos;
			}
			return nfind;
		}

		SFInt String::rfind( SFChar c ) const
		{
			SFInt pos = length - 1;
			SFInt nfind = -1;

			while( pos >= 0 )
			{
				if ( data[pos] == c )
				{
					nfind = pos;
					break;
				}
				--pos;
			}
			return nfind;
		}

		String String::substr( SFInt pos, SFInt n ) const
		{
			assert( pos >= 0 && pos < length && pos + n - 1 < length );
			String result( n );
	
			for( SFInt i = 0; i < n; ++i, ++pos )
			{
				result.data[i] = data[pos];
			}
			result.data[n] = '\0';
			return result;
		}

		String::operator SFUInt() const
		{
			//	Jenkins hash function
			SFUInt result = 0;
			for ( int i = 0; i < length; ++i )
			{
				result += data[i];
				result += (result << 10);
				result ^= (result >> 6);
			}
			result += (result << 3);
			result ^= (result >> 11);
			result += (result << 15);
			return result;
		}

		String operator+( const SFChar* c, const String& s )
		{
			String result( s.length + strlen( c ) );

			strcpy_s( result.data, result.length + 1, c );
			strcat_s( result.data, result.length + 1, s.data );

			return result;
		}
	}
}